package com.yanftch.json2ets.json2ets.views

import com.google.gson.*
import com.intellij.ui.components.JBScrollPane
import com.intellij.uiDesigner.core.GridConstraints
import com.intellij.uiDesigner.core.GridLayoutManager
import com.yanftch.json2ets.json2ets.generator.MessageDelegate
import com.yanftch.json2ets.json2ets.parser.typescript.ParseType
import java.awt.Dimension
import java.awt.Insets
import java.util.*
import javax.swing.*


@Suppress("MagicNumber")
class Json2TsForm(fileName: String? = "") {
    lateinit var rootView: JPanel
    lateinit var editor: JsonEditor
    lateinit var generateButton: JButton
    lateinit var rootObjectName: JTextField
    lateinit var fileNameLabel: JLabel
    lateinit var typeRadio: JRadioButton
    lateinit var interfaceRadio: JRadioButton
    lateinit var jsDocRadio: JRadioButton
    lateinit var classRadio: JRadioButton
    private lateinit var buttonGroup: ButtonGroup
    lateinit var formatJsonBtn: JButton
    private var listener: OnGenerateClicked? = null


    // 递归排序 JsonElement 中的所有对象
    private fun sortJsonElement(jsonElement: JsonElement): Map<String, Any> {
        val gson = GsonBuilder().setPrettyPrinting().serializeNulls().create() // 保留JSON中value为null的键值对
        val unsortedMap: Map<String, Any> = gson.fromJson<Map<String, Any>>(jsonElement, Map::class.java)

        // 创建一个 TreeMap，使其自动按键排序
        val sortedMap: MutableMap<String, Any> = TreeMap()

        // 遍历每个键值对，处理嵌套的 Map
        for ((key, value) in unsortedMap) {
            if (value is Map<*, *>) {
                // 递归排序嵌套的 JSON 对象
                sortedMap[key] = sortJsonElement(gson.toJsonTree(value))
            } else {
                sortedMap[key] = value
            }
        }
        return sortedMap
    }

    fun setFormatHandle() {
        formatJsonBtn.addActionListener {
            val json = editor.text
            json.let {
                val jsonString = try {
                    val sort = false
                    if (sort) {
                        val gson = GsonBuilder().setPrettyPrinting().serializeNulls().create() // 保留JSON中value为null的键值对
                        val jsonElement = gson.fromJson(json, JsonElement::class.java)
                        val sortedMap: Map<String, Any> = sortJsonElement(jsonElement)
                        gson.toJson(sortedMap)
                    } else {
                        val rootJsonElement = JsonParser.parseString(json)
                        val gson = GsonBuilder().setPrettyPrinting().serializeNulls().create() // 保留JSON中value为null的键值对
                        gson.toJson(rootJsonElement)
                    }

                } catch (e: JsonParseException) {
                    MessageDelegate().catchException(e, null)
                }
                editor.text = jsonString as String

//                if (json.startsWith("{")) {
//                    val jsonObject: JSONObject = JSONObject(json)
//                    val formatJson = jsonObject.toString(4)
//                    editor.text = formatJson
//                } else if (json.startsWith("[")) {
//                    val jsonArray: JSONArray = JSONArray(json)
//                    val formatJson = jsonArray.toString(4)
//                    editor.text = formatJson
//                }
            }
        }
    }

    fun setOnGenerateListener(listener: OnGenerateClicked) {
        this.listener = listener
        interfaceRadio.isSelected = true
        val radioList = listOf(interfaceRadio, jsDocRadio, typeRadio, classRadio)
        radioList.forEach {
            it.addActionListener {
                radioList
                    .filter { btn -> btn.text != it!!.actionCommand }
                    .forEach { btn -> btn.isSelected = false }
            }
        }
        generateButton.addActionListener {
            val selectedRadio = radioList.find { it.isSelected }
            selectedRadio?.let {
                val parseType = when (selectedRadio.text) {
                    "JsDoc" -> ParseType.JsDoc
                    "Type" -> ParseType.TypeStruct
                    "Class" -> ParseType.TSClass
                    "Interface" -> ParseType.InterfaceStruct
                    else -> ParseType.InterfaceStruct
                }
                val rootName = if (rootObjectName.text != "") {
                    rootObjectName.text
                } else "RootObject"
                this.listener?.onClicked(
                    rootName,
                    editor.text,
                    parseType
                )
            }

        }
    }

    private fun createUIComponents() {
        editor = JsonEditor.createEditorByClipboard()
        editor.apply {
            setOneLineMode(false)
        }
    }

    init {
        // GUI initializer generated by IntelliJ IDEA GUI Designer
        // >>> IMPORTANT!! <<<
        // DO NOT EDIT OR ADD ANY CODE HERE!
        `$$$setupUI$$$`()
        setFormatHandle()

        rootObjectName.text = fileName ?: ""
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     * @noinspection ALL
     */
    @Suppress("LongMethod")
    private fun `$$$setupUI$$$`() {
        createUIComponents()
        rootView = JPanel()
        rootView.layout = GridLayoutManager(2, 4, Insets(0, 0, 0, 0), -1, -1)
        rootView.preferredSize = Dimension(500, 500)
        val scrollPane1 = JBScrollPane()
        rootView.add(
            scrollPane1,
            GridConstraints(
                0,
                0,
                1,
                4,
                GridConstraints.ANCHOR_CENTER,
                GridConstraints.FILL_BOTH,
                GridConstraints.SIZEPOLICY_CAN_SHRINK or GridConstraints.SIZEPOLICY_WANT_GROW,
                GridConstraints.SIZEPOLICY_CAN_SHRINK or GridConstraints.SIZEPOLICY_WANT_GROW,
                null,
                null,
                null,
                0,
                false
            )
        )
        scrollPane1.add(editor)
        generateButton = JButton()
        formatJsonBtn = createFormatButton()
        generateButton.text = "Generate"
        rootView.add(
            generateButton,
            GridConstraints(
                1,
                3,
                1,
                1,
                GridConstraints.ANCHOR_CENTER,
                GridConstraints.FILL_HORIZONTAL,
                GridConstraints.SIZEPOLICY_CAN_SHRINK or GridConstraints.SIZEPOLICY_CAN_GROW,
                GridConstraints.SIZEPOLICY_FIXED,
                null,
                null,
                null,
                0,
                false
            )
        )

        rootObjectName = JTextField()
        rootView.add(
            rootObjectName,
            GridConstraints(
                1,
                2,
                1,
                1,
                GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_HORIZONTAL,
                GridConstraints.SIZEPOLICY_WANT_GROW,
                GridConstraints.SIZEPOLICY_FIXED,
                null,
                Dimension(150, -1),
                null,
                0,
                false
            )
        )
        fileNameLabel = JLabel()
        fileNameLabel.text = "Root name:"
        rootView.add(
            fileNameLabel,
            GridConstraints(
                1,
                1,
                1,
                1,
                GridConstraints.ANCHOR_WEST,
                GridConstraints.FILL_NONE,
                GridConstraints.SIZEPOLICY_FIXED,
                GridConstraints.SIZEPOLICY_FIXED,
                null,
                null,
                null,
                0,
                false
            )
        )
        buttonGroup = ButtonGroup()
        buttonGroup.add(typeRadio)
        buttonGroup.add(interfaceRadio)
        buttonGroup.add(jsDocRadio)
    }

    private fun createFormatButton(): JButton {
        return JButton()
    }

    /**
     * @noinspection ALL
     */
    fun `$$$getRootComponent$$$`(): JComponent {
        return rootView
    }

    interface OnGenerateClicked {
        fun onClicked(rootName: String, json: String, parseType: ParseType)
    }
}
